package com.googlecode.garbagecan.asmstudy.helloworld;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

public class Test {
	public static void main(String[] args) throws Exception {
		System.out.println("Before ----------");
		HelloWorld helloWorld = new HelloWorldImpl();
		helloWorld.sayHello();

		System.out.println("After ----------");
		ClassLoader loader = new HelloWorldClassLoader();
		Class clazz = loader.loadClass("com.googlecode.garbagecan.asmstudy.helloworld.HelloWorldImpl");
		Object obj = clazz.newInstance();
		helloWorld = (HelloWorld)obj;
		helloWorld.sayHello();
//		Method method = clazz.getMethod("sayHello", new Class[] {});
//		method.invoke(obj, null);
	}
}

class HelloWorldClassLoader extends ClassLoader {
	public HelloWorldClassLoader() {
		super(HelloWorldClassLoader.class.getClassLoader());
	}

	public Class loadClass(String name) throws ClassNotFoundException {
		return findClass(name);
	}

	public Class findClass(String name) {
		try {
			if(!name.equals(HelloWorldImpl.class.getName())) {
				return findSystemClass(name);
			}
		} catch (Exception ex) {
			return null;
		}
		try {
			byte[] bytes = loadClassData(name);
			Class clazz = defineClass(name, bytes, 0, bytes.length,null);
			return clazz;
		} catch (Exception e) {
			return null;
		}
	}

	private byte[] loadClassData(String name) throws IOException {
		ClassReader cr = new ClassReader(name);
		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		ClassAdapter classAdapter = new HelloWorldClassAdapter(cw);
		cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
		byte[] bytes = cw.toByteArray();
		org.apache.commons.io.FileUtils.writeByteArrayToFile(new File("target/classes/HelloWorldImpl.class"), bytes);
		return bytes;
	}
}